
/**
 * twitterapi.h
 * 
 * TwitterAPI is a wrapper of Twitter API
 * 
 * Copyright (c) 2008 Harunobu Oyama <nobukichi at gmail.com>
 * Licensed under GNU GPL version 3
 *
 */

#ifndef		TWITTER_API_INCLUDED
#define		TWITTER_API_INCLUDED

#include <boost/shared_ptr.hpp>
#include <QHttp>
#include <QBuffer>
#include "tweet.h"

class TwitterAPI : public QObject
{
	Q_OBJECT

public:
	explicit TwitterAPI(QObject* parent = 0);
	
	~TwitterAPI();

	//! cancel all the API requests and reset API's internal state
	void reset();

	//! set host name if you are using another Twitter-API compatible service
	//! e.g. setHost("twitter.com");
	void setHost(const QString& host);

	//! set twitter user name and password
	//! signalSetCredentialsDone is emitted when this operation completes, but id does not mean the credentials are atuthenticated
	//! signalAuthenticationFailure is emitted when authentication fails afterwards
	void setTwitterCredentials(const QString& userName, const QString& password);

	//! get what I have posted recently
	//! the result of this function will be asynchronously reported by signalReceivedTweets
	//! return request id
	int getMyOwnTimeline(int page = 1);

	//! get what's shown on my recent timeline
	//! the result of this function will be asynchronously reported by signalReceivedTweets
	//! return request id
	int getMyfriendsTimeline(int page = 1);

	//! get what the specified user has posted recently
	//! the result of this function will be asynchronously reported by signalReceivedTweets
	//! return request id
	int getTimelineOf(const QString& userName, int page = 1);

	//! get the list of users who the specified user is following
	//! the result of this function will be asynchronously reported by signalReceivedUserList
	//! if userName does not exist, signalGetFollowingUsersOfFailed will be emitted
	//! return request id
	int getFollowingUsersOf(const QString& userName);

	//! update my tweet (post a tweet) 
	//! return request id
	int update(const QString& newMessage);

signals:
	//! signal to report that http request to twitter server is being issued
	void signalRequestStarted();
	//! signal to report that all ongoing twitter requests are done
	void signalRequestDone();

	//! signal to receive the result of getTimelineOf/getMyfriendsTimeline/getMyOwnTimeline
	void signalReceivedTweets(int requestId, const TweetVector& tweets);

	//! signals to receive the result of getFollowingUsersOf
	void signalReceivedUserList(int requestId, const QStringList& userList);
	void signalGetFollowingUsersOfFailed(int requestId);

	//! signals to receive the result of setTwitterCredentials
	void signalSetCredentialsDone();

	//! Twitter API calls will emit this signal, if user name or password are incorrect
	//! the id of the request, which caused the authentication failure will be given
	void signalAuthenticationFailure(int requestId);

	//! signal to report a http error
	void signalDetectedHttpError(QHttp::Error error);

private:
	//! disallow copy/assign TwitterAPI instance
	TwitterAPI(const TwitterAPI&);
	TwitterAPI& operator=(const TwitterAPI&);

	//! TwitterAPI request object
	class Request {
	public:
		enum Type {
			REQ_TYPE_NIL,
			REQ_TYPE_TWEETS,
			REQ_TYPE_USER_LIST,
			REQ_TYPE_UPDATE
		};
		
		explicit Request(Type type = REQ_TYPE_NIL);
		Type type() const;
		QBuffer* responseBuffer();
		
	private:
		Type reqType;
		boost::shared_ptr<QBuffer> ptrResponseBuffer;
	};

	//! send a GET request to twitter server with the given path
	int sendGetRequest(const QString& path, Request::Type reqType);

	//! decode http response body and emit signalReceivedTweets
	void emitSignalReceivedTweets(int requestId, const QBuffer& buffre);

	//! decode http response body and emit signalReceivedUserList
	void emitSignalReceivedUserList(int requestId, const QBuffer& buffre);

	QHttp http;
	
	typedef std::map<int, Request> RequestMap;
	RequestMap activeRequests; //! map from request id returned by QHttp to Request object holding a QBuffer to receive the http response

	int authenticationRequestId;

	QHttp::Error lastHttpError;

private slots:
	//! slot to receive http response from twitter server 
	void slotRequestFinished(int id, bool error);

	void slotEmitSignalDetectedHttpError();
	void slotEmitSignalRequestStarted();
	void slotEmitSignalRequestDone();
};

#endif	//	TWITTER_API_INCLUDED

